package io.renren.modules.netty;

import cn.hutool.core.util.XmlUtil;
import io.renren.common.utils.DateUtils;
import io.renren.modules.equipment.EquipmentEntity;
import io.renren.modules.equipment.EquipmentService;
import io.renren.util.CommonUtil;
import io.renren.util.HexUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import javax.crypto.Cipher;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

@Component
@Slf4j
public class XmlService {
  @Value("${wzzjj.xml.prifix}")
  private String xml_prefix;

  private static String head = "55AA55AA";
  private static String foot = "68681616";
  @Autowired
  private EquipmentService equipmentService;

  /**
   * <meter id="001" addr="0000000abc01" com="1" tp="202" name="测试电表 1">
   *  <function id="01" coding="01B00" error="192">113009.17</function>
   *  </meter>
   * @param buildingId
   * @return
   */
  public Document report(String buildingId) {
    InputStream stream = XmlService.class.getResourceAsStream(xml_prefix + "/report.xml");
    Document document = XmlUtil.readXML(stream);
    Node building = XmlUtil.getNodeByXPath("//root/common/building_id", document);
    building.setTextContent(buildingId);
    Node time = XmlUtil.getNodeByXPath("//root/data/time", document);
    time.setTextContent(DateUtils.format(new Date(), "yyyyMMddHHmmss"));
    return document;
  }

  public String archivesAck(String buildingId,String serializ) {
    InputStream stream = XmlService.class.getResourceAsStream(xml_prefix + "/archives.xml");
    Document document = XmlUtil.readXML(stream);
    Node meterInfo = XmlUtil.getNodeByXPath("//root/instruction/meter_info", document);
    List<EquipmentEntity> equipments = equipmentService.listByBuildingId(buildingId);
    if (!CollectionUtils.isEmpty(equipments)) {
      for (int i = 0; i < equipments.size(); i++) {
        EquipmentEntity equipment = equipments.get(i);
        Element meter = document.createElement("meter");
        meter.setAttribute("id", CommonUtil.formatId(i + 1));
        meter.setAttribute("meterId", CommonUtil.formatId(i + 1));
        meter.setAttribute("addr", "00" + equipment.getSn());
        meter.setAttribute("mType", "02");
        meter.setAttribute("com", "1");
        meter.setAttribute("comType", "02");
        meter.setAttribute("tUnit", "1");
        meter.setAttribute("code", equipment.getCode());
        meter.setAttribute("ct", "1");
        meter.setAttribute("memo", equipment.getName());
        meter.setAttribute("pt", "1");
        meter.setAttribute("sampleId", "01");
        meterInfo.appendChild(meter);
      }
    }
    String msg = chageToMsg(document,serializ);
    return msg;
  }
  public  String device() {
    try {
      InputStream stream = XmlService.class.getResourceAsStream(xml_prefix + "/device.xml");
      Document document = XmlUtil.readXML(stream);
      Node buildingNode = XmlUtil.getNodeByXPath("//root/device/build_name", document);
      byte[] bytes = buildingNode.getTextContent().getBytes("GB2312");
      buildingNode.setTextContent(new String(bytes, "GB2312"));
      String msg = chageToMsg(document);
      return msg;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return null;
    }
  }
  public  String heart() {
    InputStream stream = XmlService.class.getResourceAsStream(xml_prefix+"/notify.xml");
    Document document = XmlUtil.readXML(stream);
    String msg = chageToMsg(document);
    return msg;
  }
  public  String auth() {
    InputStream stream = XmlService.class.getResourceAsStream(xml_prefix + "/request.xml");
    Document document = XmlUtil.readXML(stream);
    String msg = chageToMsg(document);
    return msg;
  }

  public  String md5(byte[] md5Bytes) {
    InputStream stream = XmlService.class.getResourceAsStream(xml_prefix + "/md5.xml");
    Document document = XmlUtil.readXML(stream);
    Node md5Node = XmlUtil.getNodeByXPath("//root/id_validate/md5", document);
    md5Node.setTextContent(HexUtils.bytesToHexString(md5Bytes));
    return chageToMsg(document);
  }

  public static String chageToMsg(Document document, String serializ) {
    try {
      byte[] xmlbyte = XmlUtil.toStr(document, false).getBytes("GB2312");
      if (xmlbyte.length % 16 != 0) {
        byte[] app = new byte[16 - xmlbyte.length % 16];
        xmlbyte = ArrayUtils.addAll(xmlbyte, app);
      }
      Cipher cipher = CommonUtil.getCipher(Cipher.ENCRYPT_MODE);
      byte[] encrypted = cipher.doFinal(xmlbyte);

      int length = encrypted.length + 4;
      String num = StringUtils.isEmpty(serializ) ? CommonUtil.getRandomNum() + "" : serializ;
      String lengthStr = Integer.toHexString(length);

      if (lengthStr.length() < 8) {
        for (int i = lengthStr.length(); i < 8; i++) {
          lengthStr = "0" + lengthStr;
        }
      }
      StringBuffer command = new StringBuffer();
      command.append(head);
      command.append(CommonUtil.reverseString(lengthStr));
      byte[] content = ArrayUtils.addAll(HexUtils.hexStr2Bytes(num), encrypted);
      command.append(HexUtils.bytesToHexString(content));
      command.append(HexUtils.bytesToHexString(HexUtils.intTo2Byte(HexUtils.CRC16_XMODEM(content))));
      command.append(foot);
//      log.info("command = "+command.toString());
      log.info("send xml is "+XmlUtil.toStr(document, false));
      return command.toString();
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return null;
    }
  }
  public static String chageToMsg(Document document) {
    return chageToMsg(document, null);
  }



}
